﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Xml;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing.Design;

namespace UmcControls.DesignInterface
{
    #region interface exposed to toolbox

    /// <summary>
    /// this interface is current assembly identifier , the AppExp package will refrence this
    /// assembly by identifying this type. never need to edit this interface
    /// </summary>
    public interface IUmcDesignInterface
    {
    }

    /// <summary>
    /// this interface expose a custom toolboxitem
    /// </summary>
    public interface IUmcToolboxItem
    {
        string ComponentFullName { get; set; }
        ToolboxItem Umcitem { get; set; }
        string UmcGroupName { get; set; }
    }
    
    /// <summary>
    /// provide toolbox
    /// </summary>
    public sealed class ToolboxProvider
    {
        public static IEnumerable<IUmcToolboxItem> GetSupportedToolboxItem()
        {
            //the list ready to return
            List<IUmcToolboxItem> retList = new List<IUmcToolboxItem>();

            IEnumerable<Type> types = (new ToolboxItemManager() as IToolboxItemManager).GetAllPossibleItemType();
            

            foreach (Type type in types)
            {
                UmcToolboxItem utbi = new UmcToolboxItem();
                utbi.Umcitem = new ToolboxItem(type);
                utbi.UmcGroupName = "UnGrouped Controls";
                utbi.ComponentFullName = type.FullName;
                AttributeCollection attribs = TypeDescriptor.GetAttributes(type);
                //deal with DisplayNameAttribute
                DisplayNameAttribute displayName =
                    attribs[typeof(DisplayNameAttribute)] as DisplayNameAttribute;
                if (displayName != null && !displayName.IsDefaultAttribute())
                {
                    utbi.Umcitem.DisplayName = displayName.DisplayName;
                }
                //deal with UmcContorlGoupNameAttribute
                UmcContorlGoupNameAttribute ugattribute =
                    attribs[typeof(UmcContorlGoupNameAttribute)] as UmcContorlGoupNameAttribute;
                if (ugattribute != null && !ugattribute.IsDefaultAttribute())
                {
                    utbi.UmcGroupName = ugattribute.GroupName;
                }
                retList.Add(utbi);
            }
            return retList;
        }
    }

    #endregion

    #region interface exposed to designer

    /// <summary>
    /// this interface should be inherited by any predined control
    /// this interface is used to deal properties which is not supported by design
    /// </summary>
    public interface IUmcPropertyStore
    {
        //add a property should be stored
        void AddUmcProperty(string property, string value);
        //remove a property should be deleted
        void RemoveUmcProperty(string property);
        //remove all stored properties
        void RemoveAllUmcProperties();
        //Get the property value
        string GetUmcProperty(string property);
        //in order to enumarate the dic
        List<KeyValuePair<string, string>> GetUmcPropertyList();
    }

    /// <summary>
    /// This interface defines the converter function from .Net control to Umc Custom control
    /// </summary>
    public interface IConverter
    {
        XmlNode[] Serialize(IComponent root, XmlDocument document);
        IComponent DeSerialize(IDesignerHost host, XmlDocument document, XmlNode[] node);
    }

    /// <summary>
    /// some umc constant
    /// </summary>
    public static class UmcConstant
    {
        //define the Body name , a const
        public static string UmcBodyName = "Body";

        public static string UmcControlNamespace = "Wicresoft.Shell.Package.AppExp.ToolboxControl";
    }

    /// <summary>
    /// wrap the UmcSerializeFactory and UmcDeSerializeFactory
    /// </summary>
    public sealed class DesignProvider
    {
        public static IConverter Create(string name)
        {
            return UmcDeSerializeFactory.Create(name);
        }
        public static IConverter Create(IComponent root)
        {
            return UmcSerializeFactory.Create(root);
        }
    }

    #endregion

    #region internal class

    /// <summary>
    /// this Attribute is used to group the controls
    /// </summary>
    [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false), Serializable]
    internal sealed class UmcContorlGoupNameAttribute : Attribute
    {
        public string GroupName { get; set; }
        public UmcContorlGoupNameAttribute(string groupName)
        {
            GroupName = groupName;
        }
    }

    //use this class to reflect a component and return a IConverter when Serialize
    internal sealed class UmcSerializeFactory
    {
        private static string ControlNamespace = UmcConstant.UmcControlNamespace + ".";

        private static Dictionary<Type, IConverter> map = new Dictionary<Type, IConverter>();

        //here the root is a .Net component
        public static IConverter Create(IComponent root)
        {
            //t is a .Net type
            Type t = root.GetType();
            if (map.ContainsKey(t))
            {
                return map[t];
            }
            else
            {
                Type umc;
                umc = Assembly.GetExecutingAssembly().GetType(ControlNamespace + "Umc" + t.Name);
                if (umc != null)
                {
                    IConverter ict = Activator.CreateInstance(umc) as IConverter;
                    map.Add(t, ict);
                    return ict;
                }
                else
                    return null;
            }
        }

    }

    //use this class to reflect a component and return a IConverter when DeSerialize
    internal sealed class UmcDeSerializeFactory
    {
        private static string ControlNamespace = UmcConstant.UmcControlNamespace + ".";

        private static Dictionary<String, IConverter> map = new Dictionary<String, IConverter>();

        public static IConverter Create(string name)
        {
            if (map.ContainsKey(name))
            {
                return map[name];
            }
            else
            {
                Type umc;
                umc = Assembly.GetExecutingAssembly().GetType(ControlNamespace + "Umc" + name);
                IConverter ict;
                if (umc != null)
                {
                    ict = Activator.CreateInstance(umc) as IConverter;
                    map.Add(name, ict);
                    return ict;
                }
                else
                {
                    umc = Assembly.GetExecutingAssembly().GetType(ControlNamespace + "UmcScript");
                    ict = Activator.CreateInstance(umc) as IConverter;
                    return ict;
                }
            }
        }

        //private static string GetUmcTypeName(string name)
        //{
        //    if (name == "MenuItem")
        //        return typeof(IUmc).Namespace + ".Umc" + typeof(MenuStrip).Name;
        //    else
        //        return typeof(IUmc).Namespace + ".Umc" + name;
        //}
    }

    internal sealed class UmcToolboxItem : IUmcToolboxItem
    {
        #region IUmcToolboxItem Members

        public ToolboxItem Umcitem
        {
            get;
            set;
        }

        public string UmcGroupName
        {
            get;
            set;
        }

        public string ComponentFullName
        {
            get;
            set;
        }

        #endregion
    }

    #endregion
}
